/*
 *  Copyright (C) 2004 Cidero, Inc.
 *
 *  Permission is hereby granted to any person obtaining a copy of 
 *  this software to use, copy, modify, merge, publish, and distribute
 *  the software for any non-commercial purpose, subject to the
 *  following conditions:
 *  
 *  The above copyright notice and this permission notice shall be included
 *  in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
 *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
 *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY IN CONNECTION WITH THE SOFTWARE.
 * 
 *  File: $RCSfile: Bridge.java,v $
 *
 */

package com.cidero.bridge;

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.logging.Logger;

import org.cybergarage.upnp.device.InvalidDescriptionException;

import com.cidero.util.MrUtil;
import com.cidero.util.AppPreferences;


/**
 * Describe class <code>UPNPBridge</code> here.
 *
 * Th UPnPBridge class serves as bridge between the UPnP world and 
 * non-UPNP devices.  The general idea is to make legacy devices that
 * are controlled via TCP/IP, IR, serial, and X10 appear as UPnP devices
 * on the network.
 *
 * This class reads a property file containing the list of supported devices
 * then instantiates the device manager for each device type. There
 * is one instance of a device manager per device type. Each device
 * manager may manage one or more instances of a device.
 *
 */

public class Bridge 
{
  private static Logger logger = Logger.getLogger("com.cidero.bridge");

  List deviceManagerList = new ArrayList();
  
  static AppPreferences pref;

  /**
   * Constructor. Reads the property file and instantiates the
   * specified DeviceManager instances
   *
   * @exception InvalidDescriptionException if an error occurs
   */
  public Bridge()
  {
    loadPreferences();

    // Load device managers specifield in preferences file
    loadDeviceManagers();
  }

  /**
   *  Load Bridge preferences. Preference information comes from 
   *  2 sources - the default set of preferences that come with the program,
   *  and the (optional) user-specific set stored in the user's home
   *  directory. The default set is located in the Java classpath under 
   *  the 'properties' subdirectory. The user-specific set is stored 
   *  in the user's home directory, under the '.cidero' subdirectory 
   */
  public static void loadPreferences()
  {
    // Load shared & user-specific preferences for this application
    pref = new AppPreferences(".cidero");

    if( ! pref.load( "Bridge", "Bridge" ) )
    {
      logger.severe("Missing preferences file - exiting");
      System.exit(-1);
    }
  }
  
  /** 
   *  Load device managers specifield in property file
   */
  public void loadDeviceManagers()
  {
    logger.fine("Entering loadDeviceManagers " );

    // Prop files for all classes stored in single flat directory 
    // by build script, so no extra path needed here...
    Properties props = MrUtil.loadProperties("Bridge.properties");

    String propStr = pref.get("deviceManagers");

		if( propStr == null )
    {
      logger.warning("No device managers specified in property file! " );
		}
    else
    {
      logger.fine("deviceManagers: " + propStr );

      String[] devManagerClasses = propStr.split(",");
    
      for( int n = 0; n < devManagerClasses.length; n++ )
      {
        logger.config("Adding bridge device manager class " 
                      + devManagerClasses[n] ); 

        BridgeDeviceManager devManager =
         (BridgeDeviceManager)MrUtil.createInstance( devManagerClasses[n] );
        
        deviceManagerList.add( devManager );
      }
    }
    
    logger.fine("Leaving loadDeviceManagers " );
  }

  public void savePreferences()
  {
    pref.saveUserPreferences( "Bridge", "Bridge" );
  }

  public static AppPreferences getPreferences()
  {
    if( pref == null )
      loadPreferences();
    
    return pref;
  }

  /**
   *  Start all device managers - they in turn start up all the 
   *  individual bridge device instances
   */
  public void start()
  {
    for( int n = 0 ; n < deviceManagerList.size() ; n++ )
    {
      BridgeDeviceManager deviceManager = 
        (BridgeDeviceManager)deviceManagerList.get(n);

      deviceManager.start();
    }
  }

  public void stop()
  {
    for( int n = 0 ; n < deviceManagerList.size() ; n++ )
    {
      BridgeDeviceManager deviceManager = 
        (BridgeDeviceManager)deviceManagerList.get(n);

      deviceManager.stop();
    }
  }


  /**
   *  Main entry point
   */
  public static void main(String args[])
  {
    try
    {
      final Bridge bridge = new Bridge();

      logger.info("Starting device bridge ");

      bridge.start();

      //
      // Make sure stop routine is invoked for all devices at shutdown
      // It is beneficial to send out UPnP bye-bye messages to all control
      // points if possible
      //
      Runtime.getRuntime().addShutdownHook( new Thread() {
        public void run() 
        {
          System.out.println("Java runtime shutting down");
          bridge.stop();  
        }
      });

      //logger.info("After start - sleep 10 secs");
    }
    catch( Exception e )
    {
      e.printStackTrace();
      System.out.println( e );
      System.exit(-1);
    }
  }

}

